package hust.rpc.handler;

import hust.rpc.constants.Constants;
import hust.rpc.pojo.Message;
import hust.rpc.serialize.SerializeUtils;
import hust.rpc.serialize.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 * 4B MagicNumber(魔数) "hust"
 * 1B Version(RPC版本号)
 * 1B Codec(编码方式)
 * 1B MessageType(消息类型)
 * 4B FullLength(消息总长度) -> 32bit -> 2^32byte -> 4GB
 * ** Body(消息数据,Object类型)
 */
@Slf4j
public class MessageEncoder extends MessageToByteEncoder<Message> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        try {
            // 写魔数
            out.writeBytes(Constants.MAGIC_NUMBER);
            // 写版本
            out.writeByte(Constants.VERSION);
            // 写编码方式
            out.writeByte(msg.getCodec());
            // 写消息类型
            out.writeByte(msg.getMessageType());

            // 记录写长度下标
            int lengthIndex = out.writerIndex();
            // 预留4byte长度字段
            out.writerIndex(lengthIndex + 4);

            // 获取序列化实现
            Serializer serializer = SerializeUtils.getSerializer(msg.getCodec());
            // 序列化消息
            byte[] body = serializer.serialize(msg.getData());

            // 计算总长度
            int fullLength = Constants.HEADER_LENGTH + body.length;
            // log.info("fullLength -> {} , bodyLength -> {} , body -> {}", fullLength, body.length, body);
            // 写消息体
            out.writeBytes(body);

            // 记录最终写下标
            int finalIndex = out.writerIndex();
            // 转移到写长度下标
            out.writerIndex(lengthIndex);
            // 写长度
            out.writeInt(fullLength);
            // 复原最终写下标
            out.writerIndex(finalIndex);
        } catch (Exception e) {
            log.error("消息编码失败: ", e);
        }
    }
}
